/*
    编译模块：采用程序替换的方式，将源文件翻译形成可执行文件
    1、编译成功，形成可执行文件
    2、编译失败，将标准错误流中的信息重定向到对应文件中，形成编译错误信息文件
    3、对外提供编译调用接口
*/
#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "../util/log.hpp"
#include "../util/util.hpp"

namespace ns_compile
{
    using namespace ns_util;

    class Compile
    {
    public:
        Compile()
        {
        }
        ~Compile()
        {
        }

        static bool compile(std::string &filename) // 不带后缀的源文件名
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(ERROR) << "创建子进程失败\n";
                return false;
            }
            else if (pid == 0)
            {
                umask(0);
                int fd = open(PathUtil::addPath(FileUtil::addSuffixComperr(filename)).c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
                if (fd < 0)
                {
                    LOG(ERROR) << "编译错误文件打开失败\n";
                    exit(1);
                }
                dup2(fd, 2); // 将标准错误流重定向到fd
                execlp("g++", "g++", "-o", PathUtil::addPath(FileUtil::addSuffixExe(filename)).c_str(),
                       PathUtil::addPath(FileUtil::addSuffixOrg(filename)).c_str(), "-D HEAD", nullptr);
                LOG(ERROR) << "g++程序替换失败\n";
                exit(2);
            }
            else
            {
                waitpid(pid, nullptr, 0);
            }
            if (FileUtil::isFileExist(PathUtil::addPath(FileUtil::addSuffixExe(filename)).c_str()))
                return true;
            else
                return false;
        }
    };
}
